class map {
  constructor(arr, difficulty, userName) {
    this.arr = arr
    this.difficulty = difficulty
    this.userName = userName
    this.canvas = document.querySelector("canvas")
    this.ctx = this.canvas.getContext("2d")
    this.x = 0
    this.y = 1
    this.bestArr = []
    this.getBest = false
    this.keyFlg = true
    this.height = 30
    this.heightIndex = 0
    this.remaining = this.arr[0].length * 10
    this.moveNum = 0
    this.timeNum = 0
    this.timeIndex = 0
    this.timer = null
    this.pause = true
    this.music = true
    this.data = localStorage.getItem("value") !== null ? JSON.parse(localStorage.getItem("value")) : []
    this.getStart()
  }
  $(dom) {
    return document.querySelector(dom)
  }
  getStart() {
    this.canvas.width = this.arr[0].length * 30
    this.canvas.height = this.arr.length * 30
    this.$(".remaining").innerHTML = `remaining steps: ${this.remaining}步`
    this.$(".steps").innerHTML = `used steps: ${this.moveNum}步`
    this.$(".gameName").innerHTML = `Nickname: ${this.userName}`
    this.$(".bjMusic").play()
    this.$(".best_btn").onclick = () => {
      this.getBest = true
    }
    this.$(".pause_btn").onclick = () => {
      cancelAnimationFrame(this.timer)
      this.pause = false
    }
    this.$(".start_btn_game").onclick = () => {
      cancelAnimationFrame(this.timer)
      this.frame()
      this.pause = true
    }
    this.$(".mute_btn").onclick = () => {
      this.music = !this.music
      this.$(".bjMusic").pause()
      this.$(".key").pause()
      this.$(".win").pause()
      this.$(".lose").pause()
    }
    this.$(".fail_cont").onclick = () => {
      this.$(".fail_cont").style.transform = `translate(-50%, -50%) scale(0)`
      this.$(".map_select").style.transform = `translate(-50%, -50%) scale(1)`
    }
    this.move()
    this.keys()
    this.frame()
  }
  draw() {
    for (let i = 0; i < this.arr.length; i++) {
      for (let j = 0; j < this.arr[i].length; j++) {
        this.arr[i][j] ? this.ctx.fillStyle = "#000" : this.ctx.fillStyle = "#fff"
        this.ctx.fillRect(j * 30, i * 30, 30, 30)
      }
    }
    if (this.getBest) {
      for (let i = 0; i < this.bestArr.length; i++) {
        this.ctx.fillStyle = "yellow"
        this.ctx.fillRect(this.bestArr[i][1] * 30, this.bestArr[i][0] * 30, 30, 30)
      }
    }

    if (this.keyFlg) {
      let img = this.$(".keys")
      this.ctx.drawImage(img, this.keyNum[1] * 30, this.keyNum[0] * 30, 30, 30)
    } else {
      this.heightIndex++
      if (this.heightIndex % 3 == 0) {
        this.height > 30 ? this.height = 30 : this.height -= 0.3
      }
    }
    this.ctx.fillStyle = "#000"
    this.ctx.fillRect((this.arr[0].length - 1) * 30, (this.arr.length - 2) * 30, 30, this.height)

    this.ctx.fillStyle = "red"
    this.ctx.fillRect(this.x * 30, this.y * 30, 30, 30)
  }
  time() {
    this.timeIndex++
    if (this.timeIndex % 60 == 0) {
      this.timeNum++
      this.$(".timer").innerHTML = `timer: ${this.timeNum}秒`
    }
  }
  clear() {
    cancelAnimationFrame(this.timer)
    this.x = 0
    this.y = 1
    this.bestArr = []
    this.getBest = false
    this.keyFlg = true
    this.height = 30
    this.heightIndex = 0
    this.remaining = this.arr[0].length * 10
    this.moveNum = 0
    this.timeNum = 0
    this.timeIndex = 0
    this.timer = null
    this.pause = true
    this.music = true
  }
  keys() {
    this.auto_road("1_0", this.arr, ["1_0"], ["1_0"]).forEach(item => {
      this.bestArr.push(item.split("_").map(Number))
    })
    let arr = []
    for (let i = 0; i < this.arr.length; i++) {
      for (let j = 0; j < this.arr[i].length; j++) {
        if (!this.arr[i][j]) arr.push([i, j])
      }
    }
    let newArr = arr.filter(item => {
      let flg = true
      this.bestArr.forEach(item2 => {
        if (item[0] == item2[0] && item[1] == item2[1]) flg = false
      })
      return flg
    })
    this.keyNum = newArr[Math.floor(Math.random() * newArr.length)]
  }
  move() {
    document.onkeydown = (e) => {
      if (this.pause) {
        if (e.key == "ArrowUp") {
          if (!this.arr[this.y - 1][this.x]) {
            this.y -= 1
            this.moveNums()
          }
        } else if (e.key == "ArrowDown") {
          if (!this.arr[this.y + 1][this.x]) {
            this.y += 1
            this.moveNums()
          }
        } else if (e.key == "ArrowLeft") {
          if (!this.arr[this.y][this.x - 1]) {
            if (this.x < 1) {
              this.x = 0
            } else {
              this.x -= 1
              this.moveNums()
            }
          }
        } else if (e.key == "ArrowRight") {
          if (!this.arr[this.y][this.x + 1]) {
            if(!this.keyFlg){
              if (this.arr[0].length - 1 !== this.x) this.x += 1
            }else{
              if (this.arr[0].length - 2 !== this.x) this.x += 1
            }
            this.moveNums()
          }
        }
        if (this.keyNum[0] == this.y && this.keyNum[1] == this.x) {
          // console.log("拿到钥匙")
          this.keyFlg = false
          if (this.music) this.$(".key").play()
        }
        if (this.x == this.arr[0].length - 1 && this.y == this.arr.length - 2) {
          if (!this.keyFlg) {
            // console.log("到达终点")
            if (this.music) this.$(".win").play()
            if (this.data) {
              this.data.push({ 'name': this.userName, 'steps': this.moveNum, 'time': this.timeNum, 'difficulty': this.difficulty })
              localStorage.setItem("value", JSON.stringify(this.data))
              this.rankingData(this.data)
            } else {
              let arr = []
              arr.push({ 'name': this.userName, 'steps': this.moveNum, 'time': this.timeNum, 'difficulty': this.difficulty })
              localStorage.setItem("value", JSON.stringify(arr))
              this.rankingData(arr)
            }
            this.$(".win_time").innerHTML = `time: ${this.timeNum}秒`
            this.$(".win_steps").innerHTML = `steps: ${this.moveNum}步`
            this.$(".game").style.transform = `translate(-50%, -50%) scale(0)`
            this.$(".win_cont").style.transform = `translate(-50%, -50%) scale(1)`
            this.clear()
            this.$(".win_cont_again").onclick = () => {
              this.$(".win_cont").style.transform = `translate(-50%, -50%) scale(0)`
              this.$(".map_select").style.transform = `translate(-50%, -50%) scale(1)`
            }
            this.$(".win_ranking").onclick = () => {
              this.$(".win_cont").style.transform = `translate(-50%, -50%) scale(0)`
              this.$(".ranking").style.transform = `translate(-50%, -50%) scale(1)`
            }
          }
        }
        if (this.remaining < 1) {
          console.log("游戏结束")
          this.$(".game").style.transform = `translate(-50%, -50%) scale(0)`
          this.$(".fail_cont").style.transform = `translate(-50%, -50%) scale(1)`
          if (this.music) this.$(".lose").play()
          this.clear()
        }
      }
    }
  }
  rankingData(arr) {
    arr.sort((a, b) => {
      return a.time - b.time ? a.time - b.time : a.steps - b.steps
    })
    let easyArr = [], normalArr = [], hardArr = []
    arr.forEach((item, index) => {
      if (item.difficulty == 'easy') {
        easyArr.push(item)
        this.$(".box").innerHTML += `
          <ul>
            <li>${index + 1}</li>
            <li>${item.name}</li>
            <li>${item.time}秒</li>
            <li>${item.steps}步</li>
          </ul>
        `
      }
      if (item.difficulty == 'normal') normalArr.push(item)
      if (item.difficulty == 'hard') hardArr.push(item)
    })
    this.$(".rank_easy").onclick = () => {
      this.nodeCreate(easyArr)
    }
    this.$(".rank_normal").onclick = () => {
      this.nodeCreate(normalArr)
    }
    this.$(".rank_hard").onclick = () => {
      this.nodeCreate(hardArr)
    }
  }
  nodeCreate(arr) {
    this.$(".box").innerHTML = ''
    arr.forEach((item, index) => {
      this.$(".box").innerHTML += `
        <ul>
          <li>${arr[index].time == arr[index - 1]?.time && arr[index].step == arr[index - 1]?.step ? index : index + 1}</li>
          <li>${item.name}</li>
          <li>${item.time}秒</li>
          <li>${item.steps}步</li>
        </ul>
      `
    })
  }
  moveNums() {
    this.moveNum += 1
    this.$(".steps").innerHTML = `used steps: ${this.moveNum}步`
    this.remaining < 1 ? this.remaining = 0 : this.remaining -= 1
    this.$(".remaining").innerHTML = `remaining steps: ${this.remaining}步`
  }
  auto_road(start, arr, r_road = [], checked = []) {
    let [x, y] = start.split("_").map(Number)
    let ok = []
    if (arr[x + 1] && arr[x + 1][y] === 0 && checked.indexOf((x + 1) + "_" + y) < 0) ok.push((x + 1) + "_" + y)
    if (arr[x - 1] && arr[x - 1][y] === 0 && checked.indexOf((x - 1) + "_" + y) < 0) ok.push((x - 1) + "_" + y)
    if (arr[x][y + 1] === 0 && checked.indexOf(x + "_" + (y + 1)) < 0) ok.push(x + "_" + (y + 1))
    if (arr[x][y - 1] === 0 && checked.indexOf(x + "_" + (y - 1)) < 0) ok.push(x + "_" + (y - 1))

    if (ok.length > 0) {
      let ran = Math.floor(Math.random() * ok.length)
      let [x, y] = ok[ran].split("_").map(Number)
      r_road.push(x + "_" + y)
      checked.push(x + "_" + y)
      return this.auto_road(x + "_" + y, arr, r_road, checked)
    } else {
      if (r_road[r_road.length - 1] == (arr.length - 2) + "_" + (arr[0].length - 1)) {
        return r_road
      }
      r_road.pop()
      if (r_road.length > 0) {
        return this.auto_road(r_road[r_road.length - 1], arr, r_road, checked)
      } else {
        return r_road
      }
    }
  }
  frame() {
    this.timer = requestAnimationFrame(() => {
      this.frame()
    })
    this.draw()
    this.time()
  }
}

export { map }